package com.wu.flandre.configuration;

import ch.qos.logback.classic.spi.CallerData;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.db.DBAppenderBase;
import org.springframework.context.annotation.Configuration;

import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Timestamp;

/**
 * LogDBAppender <br/>
 *
 * @author 50816 <br/>
 * @date 2019/12/14 2:18 <br/>
 */
@Configuration
public class LogDbAppender extends DBAppenderBase<ILoggingEvent> {

    private static final Method GET_GENERATED_KEYS_METHOD;
    private String insertSQL;

    /**
     * LOG_ID 日志的主键
     */
    private static final String LOG_MARK = "-";
    /**
     * LOG_LEAVE 日志等级
     */
    private static final int LOG_LEAVE = 1;
    /**
     * LOG_TIME 日志时间
     */
    private static final int LOG_TIME = 2;
    /**
     * MESSAGE日志内容
     */
    private static final int MESSAGE = 3;
    /**
     * LOG_CLASS 日志主类
     */
    private static final int LOG_CLASS = 4;


    static final StackTraceElement EMPTY_CALLER_DATA = CallerData.naInstance();

    static {
        // PreparedStatement.getGeneratedKeys() method was added in JDK 1.4
        Method getGeneratedKeysMethod;
        try {
            // the
            getGeneratedKeysMethod = PreparedStatement.class.getMethod("getGeneratedKeys", (Class[]) null);
        } catch (Exception ex) {
            getGeneratedKeysMethod = null;
        }
        GET_GENERATED_KEYS_METHOD = getGeneratedKeysMethod;
    }

    @Override
    public void start() {
        // 将写好的sql语句赋值给insertSQL
        insertSQL = buildInsertSQL();
        super.start();
    }

    /**
     * 重写sql
     *
     * @return
     */
    private static String buildInsertSQL() {
        return "INSERT INTO `SystemLog`(`Logleave`,`LogTime`,`Message`,`LogClass`)" +
                "VALUES (?,?,?,?)";
    }

    @Override
    protected Method getGeneratedKeysMethod() {
        return GET_GENERATED_KEYS_METHOD;
    }

    @Override
    protected String getInsertSQL() {
        return insertSQL;
    }

    /**
     * 主要修改的方法
     *
     * @param stmt
     * @param event
     * @throws SQLException
     */
    private void bindLoggingEventWithInsertStatement(PreparedStatement stmt, ILoggingEvent event) throws SQLException {
        // event.getFormattedMessage() 日志打印内容
        String message = event.getMessage();
        // 如果只想存储自己打印的日志，可以这样写日志：logger.info("> XXXX")
        // 判断日志消息首字母为 - 的日志，记录到数据库表
        if (message.startsWith(LOG_MARK)) {
            stmt.setString(LOG_LEAVE, event.getLevel().toString());
            stmt.setTimestamp(LOG_TIME, new Timestamp(event.getTimeStamp()));
            stmt.setString(MESSAGE, message);
            stmt.setString(LOG_CLASS, event.getLoggerName());
        }

    }

    @Override
    protected void subAppend(ILoggingEvent eventObject, Connection connection, PreparedStatement statement) throws Throwable {
        bindLoggingEventWithInsertStatement(statement, eventObject);
        // This is expensive... should we do it every time?
        int updateCount = statement.executeUpdate();
        if (updateCount != 1) {
            addWarn("Failed to insert loggingEvent");
        }
    }

    @Override
    protected void secondarySubAppend(ILoggingEvent eventObject, Connection connection, long eventId) throws Throwable {

    }
}
